# -*- coding: utf-8 -*-     

"""DONATO - Message WeChat Bot
This is a program that automating web WeChat mainly based on itchat.
Util now, DONATO can record the group messaging history and reply to specific command as templated

Example:
	@Donato m :   http://wedroid.zhongtouwan.com/message/37ld7

Environment variable:
	export DONATO_PROFILE='Dev', which can be configed in config.py

Git:
	http://git.oschina.net/uchang/donato

Author:
	Chang Liu
"""

import itchat
import datetime
import hashlib
from hashids import Hashids
import os
import json
import unicodedata
import redis
import gevent
from rq import Queue
from itchat.content import *
from sqlalchemy import or_
from lxml import etree
from donato import app, logger
from donato.database import Session, Message, GroupMember, Contacter, Droid, GroupMentionLog, Command
from donato.worker import msg_save
from donato.util import CardContent, SharingContent
import sys  

reload(sys)  
sys.setdefaultencoding('utf8')

firstSysMsg = True

r = redis.Redis(host = app.config['REDIS_HOST'], port = app.config['REDIS_PORT'], password = app.config['REDIS_PASSWORD'], db = app.config['REDIS_DB'])

create_q = Queue('high',connection = r)

save_q = Queue('normal',connection = r)

live_q = Queue('low',connection = r)

hashids = Hashids(salt='star wars', min_length=5)

session = Session()

def auto_reply(msg):
	"""Auto reply first directly before saving
	Args:
		msg(dict): message captured
	"""
	session.close()
	group = session.query(Contacter).filter(Contacter.nick_name == msg['User']['NickName']).filter(Contacter.droid_id == current_droid).first()

	kiword = msg['Content']
	if '\xe2\x80\x85' in kiword:
		kiword = msg['Content'].split('\xe2\x80\x85', 1)[1]
	else:
		kiword = msg['Content'].split(' ', 1)[1]

	if not kiword:
		itchat.send(app.config['RESPONSE_DOMAIN'] + '/help', msg['FromUserName'])

	if kiword == 'm':
		str = 'help'
		if group:
			str = 'message/'+group.hashcode
		itchat.send(app.config['RESPONSE_DOMAIN']+'/%s' % (str), msg['FromUserName'])

	command = session.query(Command).filter(or_(Command.keyword == kiword, Command.alias == kiword)).first()

	if command:
		if (command.template_type == 'TEXT') or (command.template_type == 'URL'):
			itchat.send('%s' % (command.template), msg['FromUserName'])
		elif command.template_type == 'IMAGE':
			itchat.send_image(command.template, msg['FromUserName'])
		else:
			pass

	return command

@itchat.msg_register(TEXT, isGroupChat=True)
def text_recv(msg):
	""" TEXT message receiving
	Args:
		msg(dict): message captured
	"""
	logger.info('receiving [{0}] message from [{1}] in group [{2}]'.format(msg['Type'], msg['ActualNickName'].encode('utf-8'), msg['User']['NickName']))
	
	command = Command()
	if msg['isAt']:
		command = auto_reply(msg)

	# msg_save(msg, msg['Content'], 'TEXT',command=command)
	# q.enqueue_call(func=msg_save,args=(msg, msg['Content'], 'TEXT', command))
	save_q.enqueue_call(func=msg_save, args=(msg['ActualUserName'], msg['ActualNickName'], msg['isAt'], msg['MsgId'], msg['User'],msg['CreateTime'], msg['Content'], 'TEXT', command))
	# if (msg['isAt']):
	# 	grouplog_save(msg)

@itchat.msg_register(SHARING, isGroupChat=True)
def share_recv(msg):
	""" SHARING message receiving
	Args:
		msg(dict): message captured
	"""
	logger.info('receiving [{0}] message from [{1}] in group [{2}]'.format(msg['Type'], msg['ActualNickName'].encode('utf-8'), msg['User']['NickName']))

	xmlstr = msg['Content']
	tree = etree.XML(xmlstr)
	tree[0].xpath("//msg/appmsg/des")[0].text

	content = json.dumps(SharingContent().set_appMessageType("URL")
										.set_appName(tree[0].xpath("//msg/appinfo/appname")[0].text)
										.set_dataUrl(tree[0].xpath("//msg/appmsg/dataurl")[0].text)
										.set_description(tree[0].xpath("//msg/appmsg/des")[0].text)
										.set_lowDataUrl(tree[0].xpath("//msg/appmsg/lowdataurl")[0].text)
										.set_lowUrl(tree[0].xpath("//msg/appmsg/lowurl")[0].text)
										.set_thumbUrl(tree[0].xpath("//msg/appmsg/thumburl")[0].text)
										.set_title(tree[0].xpath("//msg/appmsg/title")[0].text)
										.set_url(tree[0].xpath("//msg/appmsg/url")[0].text)
										.to_dict(), ensure_ascii=False)

	# q.enqueue_call(func=msg_save,args=(msg, content, 'SHARE'))
	save_q.enqueue_call(func=msg_save, args=(msg['ActualUserName'], msg['ActualNickName'], msg['isAt'], msg['MsgId'], msg['User'],msg['CreateTime'],content, 'SHARE'))

@itchat.msg_register(CARD, isGroupChat=True)
def card_recv(msg):
	""" CARD message receiving
	Args:
		msg(dict): message captured
	"""
	logger.info('receiving [{0}] message from [{1}] in group [{2}]'.format(msg['Type'], msg['ActualNickName'].encode('utf-8'), msg['User']['NickName']))

	content = json.dumps(CardContent().set_Alias(msg['Text']['Alias'])
									.set_City(msg['Text']['City'])
									.set_Content("")
									.set_NickName(msg['Text']['NickName'])
									.set_Province(msg['Text']['Province'])
									.set_Sex(msg['Text']['Sex'])
									.set_UserName(msg['Text']['UserName'])
									.set_headImgUrl(get_avatar(userName = msg['Text']['UserName'])).to_dict(), ensure_ascii=False)

	#msg_save(msg, content, 'SHARECARD')
	# q.enqueue_call(func=msg_save,args=(msg, content, 'SHARECARD'))
	save_q.enqueue_call(func=msg_save, args=(msg['ActualUserName'], msg['ActualNickName'], msg['isAt'], msg['MsgId'], msg['User'],msg['CreateTime'],content, 'SHARECARD'))

@itchat.msg_register(NOTE, isGroupChat=True)
def note_recv(msg):
	""" NOTE message receiving
	Args:
		msg(dict): message captured
	"""
	logger.info('receiving [{0}] message from [{1}] in group [{2}]'.format(msg['Type'], msg['ActualNickName'].encode('utf-8'), msg['User']['NickName']))

	# msg_save(msg, msg['Content'], 'SYSNOTICE')
	# q.enqueue_call(func=msg_save,args=(msg, msg['Content'], 'SYSNOTICE'))
	save_q.enqueue_call(func=msg_save, args=(msg['ActualUserName'], msg['ActualNickName'], msg['isAt'], msg['MsgId'], msg['User'],msg['CreateTime'],msg['Content'], 'SYSNOTICE'))

@itchat.msg_register([PICTURE, VIDEO, RECORDING, ATTACHMENT], isGroupChat=True)
def multimedia_recv(msg):
	""" IMAGE, VOICE, VIDEO, ATTACHMENT message receiving
	Args:
		msg(dict): message captured
	"""
	logger.info('receiving [{0}] message from [{1}] in group [{2}]'.format(msg['Type'], msg['ActualNickName'].encode('utf-8'), msg['User']['NickName']))

	fileNameSubs = msg['FileName'].split('.')

	fileNameOnly = hashlib.sha224(fileNameSubs[0].encode('utf-8')).hexdigest()

	fileType = 'image'
	msgType = 'IMAGE'
	if msg['Type'] == 'Video':
		fileType = 'video'
		msgType = 'VIDEO'
	if msg['Type'] == 'Attachment':
		fileType = 'attachment'
		msgType = 'ATTACHMENT'
	if msg['Type'] == 'Recording':
		fileType = 'voice'
		msgType = 'VOICE'

	save_path = app.config['UPLOAD_PATH'] + fileType + '/' + datetime.datetime.today().strftime('%Y%m%d') + '/'
	if not os.path.exists(save_path):
		os.makedirs(save_path)

	file_path = save_path + fileNameOnly + '.' + fileNameSubs[1]
	# msg_save(msg, file_path, msgType)
	save_q.enqueue_call(func=msg_save, args=(msg['ActualUserName'], msg['ActualNickName'], msg['isAt'], msg['MsgId'], msg['User'],msg['CreateTime'],file_path, msgType))
	logger.info('Downloading File To [{0}]'.format(file_path))
	msg['Text'](file_path)

	# else:
	#     ins = itchat.instanceList[0]
	#     fullContact = ins.memberList + ins.chatroomList + ins.mpList
	#     print('** Uin Updated **')
	#     for username in msg['Text']:
	#         member = itchat.utils.search_dict_list(
	#             fullContact, 'UserName', username)
	#         print(('%s: %s' % (
	#             member.get('NickName', ''), member['Uin']))
	#             .encode(sys.stdin.encoding, 'replace'))

def get_avatar(userName=None, chatroomUserName=None):
	"""Generate path of avatar files of all contactors and groupmember
	Args:
		userName(str): Friend od GroupMember username
		chatroomUserName(str): Group username
	Returns:
		String of avatar picture file path
	"""
	nameStr = userName if chatroomUserName is None else (userName+chatroomUserName) if userName is not None else chatroomUserName
	avatarName = hashlib.sha224(nameStr).hexdigest()
	save_path = app.config['UPLOAD_PATH'] + 'avatar/' + datetime.datetime.today().strftime('%Y%m%d') + '/'
	if not os.path.exists(save_path):
		os.makedirs(save_path)

	file_path = save_path + avatarName + '.png'

	itchat.get_head_img(userName = userName, chatroomUserName = chatroomUserName, picDir = file_path)

	return file_path

def init_login():
	"""Retrive bot info
	Returns:
		load_droid(Droid): current bot
	"""
	init_user = itchat.web_init()['User']

	logger.info('init user is [{0}]'.format(json.dumps(init_user)))

	load_droid = session.query(Droid).filter(Droid.nick_name==init_user['NickName']).first()
	if not load_droid:
		new_droid = Droid(name = init_user['NickName'],
						  contact_flag = init_user['ContactFlag'],
						  head_img_url = get_avatar(userName=init_user['UserName']),
						  member_count = 0,
						  nick_name = init_user['NickName'],
						  remark_name = init_user['RemarkName'],
						  sex = init_user['Sex'],
						  signature = init_user['Signature'],
						  username = init_user['UserName'])
		session.add(new_droid)
		load_droid = new_droid
		session.commit()
	else:
		load_droid.sex = init_user['Sex']
		load_droid.signature = init_user['Signature']
		load_droid.username = init_user['UserName']
		load_droid.head_img_url = get_avatar(userName=init_user['UserName'])
		load_droid.remark_name = init_user['RemarkName']
		session.commit()

	logger.info('Droid [{0}] Load or Create Success'.format(load_droid.nick_name.encode('utf-8')))

	return load_droid
	#gevent.killall([initload])



logger.info('Donato_bot is using profile: [{0}]'.format(app.config['PROFILE']))

# Scan qrcode and login
itchat.auto_login(picDir='donato/static/QR.png')

# initload = gevent.spawn(init_login)
# startrun = gevent.spawn(itchat.run)
# gevent.joinall([initload, startrun])

# itchat.auto_login(enableCmdQR=2)

itchat.dump_login_status()
current_droid = init_login()

# start receiving messages
itchat.run()

